package com.ffad.frame.db.core;


import java.util.HashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

import javax.sql.DataSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedResource;

import com.ffad.frame.db.enums.DataSourceType;

@SuppressWarnings("all")
@ManagedResource
public class ReplicationDataSource extends AbstractRoutingDataSource implements BeanNameAware {
	private static final Logger LOGGER = LoggerFactory.getLogger(ReplicationDataSource.class);
	private AtomicBoolean verbose = new AtomicBoolean(false);
	private String beanName;
	private String name;
	// 项目启动时会注入配置中对应的DataSource
	private DataSource writeDataSource;
	private DataSource readDataSource_1;
	private DataSource readDataSource_2;
	
	private static final AtomicBoolean query_1_Enabled = new AtomicBoolean(true);
	private static final AtomicBoolean query_2_Enabled = new AtomicBoolean(true);
	private AtomicInteger count = new AtomicInteger(0);
	
	private int readDsSize = 2;
	
	/**
	 * 实现该方法：动态切换数据源
	 * 父类中为抽象方法
	 */
	protected Object determineCurrentLookupKey() {
		String dsTypeKey = DataSourceContextHolder.getReadOrWrite();  
        
        if(dsTypeKey == null){
        	LOGGER.error("ReplicationDataSource determineCurrentLookupKey() dataSource key is null");
        	LOGGER.info("返回默认的dataSource");
            // throw new NullPointerException("数据库路由时，决定使用哪个数据库源类型不能为空..."); 
            return DataSourceType.WRITE.getType();  
        }  
        
        if (dsTypeKey.equals(DataSourceType.WRITE.getType())){  
        	LOGGER.info("ReplicationDataSource determineCurrentLookupKey() 切换 WRITE");
            return DataSourceType.WRITE.getType();  
        }
        
        LOGGER.info("ReplicationDataSource determineCurrentLookupKey() 切换 READ");
        //读库， 简单负载均衡  
        String readDS = "readDataSource_" ;
        int number = count.getAndAdd(1);
        int lookupKey = number % readDsSize;  
        String dsName = readDS + (lookupKey+1) ;
        LOGGER.info("使用读数据源：{}",dsName);
        return dsName;
	}
	

	/**
	 * 复写
	 */
	protected DataSource determineTargetDataSource() {
		DataSource targetDataSource = super.determineTargetDataSource();
		LOGGER.info("ReplicationDataSource determineTargetDataSource() targetDataSource :{}",targetDataSource); 
		return targetDataSource;
	}

	// 根据配置文件中属性的配置注入
		public void setWriteDataSource(DataSource writeDataSource) {
			this.writeDataSource = writeDataSource;
			this.setDefaultTargetDataSource(writeDataSource);
			this.setTargetDataSources();
		}
		
		// 根据配置文件中属性的配置注入
		public void setReadDataSource_1(DataSource readDataSource_1) {
			this.readDataSource_1 = readDataSource_1;
			this.setTargetDataSources();
		}
		
		
		// 根据配置文件中属性的配置注入
		public void setReadDataSource_2(DataSource readDataSource_2) {
			this.readDataSource_2 = readDataSource_2;
			this.setTargetDataSources();
		}


	/**
	 * 设置父类中的集成属性 targetDataSources
	 * 
	 */
	private void setTargetDataSources() {
		HashMap m = new HashMap();
		if (this.writeDataSource != null) {
			m.put(ReplicationDataSource.Key.writeDataSource.name(), this.writeDataSource);
		}

		if (this.readDataSource_1 != null) {
			m.put(ReplicationDataSource.Key.readDataSource_1.name(), this.readDataSource_1);
		}
		
		if (this.readDataSource_2 != null) {
			m.put(ReplicationDataSource.Key.readDataSource_2.name(), this.readDataSource_2);
		}

		// 进行设置 
		super.setTargetDataSources(m);
	}
	
	public void setBeanName(String name) {
		this.beanName = name;
	}

	@ManagedAttribute
	public String getName() {
		return this.name != null ? this.name : this.beanName;
	}

	public void setName(String name) {
		this.name = name;
	}

	@ManagedAttribute
	public boolean isVerbose() {
		return this.verbose.get();
	}

	@ManagedAttribute
	public void setVerbose(boolean verbose) {
		this.verbose.set(verbose);
	}
	
	@ManagedAttribute
	public boolean isQuery_1_Enabled() {
		return query_1_Enabled.get();
	}

	@ManagedAttribute
	public void setQuery_1_Enabled(boolean query_1_Enabled) {
		ReplicationDataSource.query_1_Enabled.set(query_1_Enabled);
	}
	
	@ManagedAttribute
	public boolean isQuery_2_Enabled() {
		return query_2_Enabled.get();
	}

	@ManagedAttribute
	public void setQuery_2_Enabled(boolean query_2_Enabled) {
		ReplicationDataSource.query_2_Enabled.set(query_2_Enabled);
	}
	
	private static enum Key {
		readDataSource_1,readDataSource_2,writeDataSource ;
	}
}